package ln.think.aop.ast.demo.getter;


import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.*;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

// 表示该处理器需要处理的注解
// https://blog.mythsman.com/post/5d2c11c767f841464434a3bf/#:~:text=Lombok%201%20%E4%BB%A3%E7%A0%81%20Lombok%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%EF%BC%8C%E6%BA%90%E4%BB%A3%E7%A0%81%E6%89%98%E7%AE%A1%E5%9C%A8%20GITHUB%2Frzwitserloot%20%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E5%9C%A8maven%E9%87%8C%E5%BC%95%E7%94%A8%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E6%B7%BB%E5%8A%A0%E4%B8%8B%E4%BE%9D%E8%B5%96%3A%20%3Cdependency%3E%20%3CgroupId%3E,%E5%88%A9%E7%94%A8JSR269%20api%20%28Pluggable%20Annotation%20Processing%20API%20%29%E5%88%9B%E5%BB%BA%E7%BC%96%E8%AF%91%E6%9C%9F%E7%9A%84%E6%B3%A8%E8%A7%A3%E5%A4%84%E7%90%86%E5%99%A8%20
@SupportedAnnotationTypes("ln.think.ast.demo.getter.MyGetter")
// 表示该处理器支持的源码版本
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class GetterProcessor extends AbstractProcessor {
    
    private Messager messager;
    private JavacTrees trees;
    private TreeMaker treeMaker;
    private Names names;

    /**
     * 通过ProcessingEnvironment来获取编译阶段的一些环境信息
     *
     * @param processingEnv environment to access facilities the tool framework
     *                      provides to the processor
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
        
    }

    /**
     * process主要是实现具体逻辑的地方，也就是对AST进行处理的地方
     *
     * @param annotations the annotation types requested to be processed
     * @param roundEnv    environment for information about the current and prior round
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // 利用roundEnv的getElementsAnnotatedWith方法过滤出被Getter这个注解标记的类，并存入set
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(MyGetter.class);
        set.forEach(element -> {
            // 遍历这个set里的每一个元素，并生成jCTree这个语法树
            JCTree jcTree = trees.getTree(element);
            // 创建一个TreeTranslator，并重写其中的visitClassDef方法，这个方法处理遍历语法树得到的类定义部分jcClassDecl
            jcTree.accept(new TreeTranslator() {
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    // 创建一个jcVariableDeclList保存类的成员变量
                    List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
                    
                    // 遍历jcTree的所有成员(包括成员变量和成员函数和构造函数)，过滤出其中的成员变量，并添加进jcVariableDeclList
                    for (JCTree tree : jcClassDecl.defs) {
                        if (tree.getKind().equals(Tree.Kind.VARIABLE)) {
                            // 将jcVariableDeclList的所有变量转换成需要添加的getter方法，并添加进jcClassDecl的成员中
                            JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) tree;
                            jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
                        }
                    }
                    
                    // 调用默认的遍历方法遍历处理后的jcClassDecl
                    jcVariableDeclList.forEach(jcVariableDecl -> {
                        messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");
                        jcClassDecl.defs = jcClassDecl.defs.prepend(makeGetterMethodDecl(jcVariableDecl));
                    });
                    
                    // 利用上面的TreeTranslator去处理jcTree
                    super.visitClassDef(jcClassDecl);
                }
            });
        });

        return true;
    }

    private JCTree makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        statements.append(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName())));
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
        return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), getNewMethodName(jcVariableDecl.getName()), jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(), body, null);
    }

    private Name getNewMethodName(Name name) {
        String s = name.toString();
        return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));
    }
}
